﻿//#define USE_DUNGEONBUDDY_DLL

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CommonBehaviors.Actions;
using Styx;
using Styx.CommonBot;
using Styx.TreeSharp;
using Styx.Pathing;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWCache;
using Styx.WoWInternals.WoWObjects;
using Action = Styx.TreeSharp.Action;
#if USE_DUNGEONBUDDY_DLL
using Bots.DungeonBuddyDll;
using Bots.DungeonBuddyDll.Profiles;
using Bots.DungeonBuddyDll.Attributes;
using Bots.DungeonBuddyDll.Helpers;


namespace Bots.DungeonBuddyDll.Dungeon_Scripts.Mists_of_Pandaria
#else
using Bots.DungeonBuddy.Profiles;
using Bots.DungeonBuddy.Attributes;
using Bots.DungeonBuddy.Helpers;
namespace Bots.DungeonBuddy.Dungeon_Scripts.Mists_of_Pandaria
#endif
{
    public class ScarletMonasteryHeroic : Dungeon
    {
        #region Overrides of Dungeon

        public override uint DungeonId
        {
            get { return 474; }
        }

        public override WoWPoint Entrance
        {
            get { return new WoWPoint(2920.317, -799.8921, 160.3323); }
        }

        public override WoWPoint ExitLocation
        {
            get { return new WoWPoint(1124.471, 504.2796, 0.9892024); }
        }

        public override bool IsComplete
        {
            get
            {
                return Me.QuestLog.GetQuestById(UntoDustThouShaltReturnQuestId) == null && base.IsComplete;
            }
        }

        public override void OnEnter()
        {
            _checkForZealot = false;
        }

        public override void RemoveTargetsFilter(List<WoWObject> units)
        {
            units.RemoveAll(
                ret =>
                {
                    var unit = ret as WoWUnit;
                    if (unit != null)
                    {
                        if (unit.Entry == TrainingDummyId || unit.Entry == TrainingDummyId2)
                            return true;
                        // ignore npcs that are fighting other npcs
                        if ((unit.Entry == ScarletCenturionId || unit.Entry == ZombifiedCorpseId || unit.Entry == PileOfCorpsesId) && !unit.TaggedByMe && unit.Combat && Me.Combat)
                            return true;
                        // ignore brother korloff if he's near other unfriendlies
                        if (unit.Entry == BrotherKorloffId && !unit.Combat && ScriptHelpers.GetUnfriendlyNpsAtLocation(() => unit.Location, 25, u => u.Entry != BrotherKorloffId).Any())
                            return true;
                        // ignore brother korloff if I'm melee and he's casting firestorm kick
                        if (unit.Entry == BrotherKorloffId && unit.CastingSpellId == FirestormKickId && Me.IsMelee())
                            return true;
                        // kill this zealot before engaging CommanderDurand
                        if (unit.Entry == CommanderDurand && !unit.Combat && ScriptHelpers.GetUnfriendlyNpsAtLocation(() => _scarletZealotLoc, 10, u => u.Entry == ScarletZealot).Any())
                            return true;
                    }
                    return false;
                });
        }

        public override void IncludeTargetsFilter(List<WoWObject> incomingunits, HashSet<WoWObject> outgoingunits)
        {
            foreach (var obj in incomingunits)
            {
                var unit = obj as WoWUnit;
                if (unit != null)
                {
                    if (unit.Entry == ScarletZealot && !Me.Combat && Me.IsTank() && unit.Location.DistanceSqr(_scarletZealotLoc) <= 10 * 10)
                        outgoingunits.Add(unit);

                }
            }
        }

        public override void WeighTargetsFilter(List<Targeting.TargetPriority> units)
        {
            foreach (var priority in units)
            {
                var unit = priority.Object as WoWUnit;
                if (unit != null)
                {
                    if (unit.Entry == PileOfCorpsesId)
                        priority.Score += 300;

                    // if (unit.Entry == EmpoweredZombie && StyxWoW.Me.IsDps())
                    //     priority.Score += 500;

                    if (unit.Entry == EvictedSoul && StyxWoW.Me.IsDps())
                        priority.Score += 400;
                }
            }
        }

        #endregion

        private const uint PileOfCorpsesId = 59722;
        private const uint EmpoweredZombie = 59930;
        private const uint EvictedSoul = 59974;
        private const uint ScarletCenturionId = 59746;
        private const uint ZombifiedCorpseId = 59771;
        private const uint TrainingDummyId = 60197;
        private const uint TrainingDummyId2 = 64446;
        private const uint BrotherKorloffId = 59223;
        private const uint ScorchedEarth = 59507;
        private const uint ScarletZealot = 58590;
        private const uint CommanderDurand = 60040;
        const int FirestormKickId = 113764;
        private const int UntoDustThouShaltReturnQuestId = 31516;
        private const uint HighInquisitorWhitemaneId = 3977;
        private const uint BladesOfTheAnointedId = 87390;

        private static LocalPlayer Me
        {
            get { return StyxWoW.Me; }
        }

        readonly WoWPoint _scarletZealotLoc = new WoWPoint(760.7621, 551.4827, 12.80546);

        [EncounterHandler(0)]
        public Composite RootBehavior()
        {
            WoWUnit whiteMane = null;
            PlayerQuest untoDustThouShaltReturnQuest = null;

            return new PrioritySelector(
                new Decorator(ctx =>
                    (untoDustThouShaltReturnQuest = Me.QuestLog.GetQuestById(UntoDustThouShaltReturnQuestId)) != null &&
                    !Me.Combat &&
                    (whiteMane = ObjectManager.GetObjectsOfType<WoWUnit>().FirstOrDefault(u => u.Entry == HighInquisitorWhitemaneId && u.IsDead)) != null,
                    new PrioritySelector(

                        new Decorator(ctx => !untoDustThouShaltReturnQuest.IsCompleted && whiteMane.Distance > 5,
                            new Action(ctx => Navigator.MoveTo(whiteMane.Location))),

                        new Decorator(ctx => !untoDustThouShaltReturnQuest.IsCompleted && whiteMane.Distance <= 5,
                            new Action(ctx => Me.BagItems.FirstOrDefault(u => u.Entry == BladesOfTheAnointedId).UseContainerItem()))
                        ))
                );
        }

        [EncounterHandler(59706, "Fuel Tank", Mode = CallBehaviorMode.Proximity, BossRange = 10)]
        public Composite FuelTankEncounter()
        {
            return new Decorator<WoWUnit>(
                fuelTank => fuelTank.TransportGuid == 0 && Me.Combat,
                new PrioritySelector(
                    new Decorator<WoWUnit>(fuelTank => fuelTank.WithinInteractRange, new Helpers.Action<WoWUnit>(fuelTank => fuelTank.Interact())),
                    new Decorator<WoWUnit>(fuelTank => !fuelTank.WithinInteractRange, new Helpers.Action<WoWUnit>(fuelTank => Navigator.MoveTo(fuelTank.Location)))));
        }

        [EncounterHandler(59789, "Thalnos the Soulrender")]
        public Composite ThalnostheSoulrenderEncounter()
        {
            const int spiritGaleSpellId = 115289;
            const uint spiritGaleObjectId = 2857;
            WoWUnit boss = null;
            return new PrioritySelector(
                ctx => boss = ctx as WoWUnit,
                ScriptHelpers.CreateDispellParty("Evict Soul", ScriptHelpers.PartyDispellType.Magic),
                ScriptHelpers.CreateInterruptCast(() => boss, spiritGaleSpellId),
                ScriptHelpers.CreateRunAwayFromBad(ctx => true, 4, spiritGaleObjectId),
                ScriptHelpers.CreateRunAwayFromLocation(
                    ctx => true,
                    2,
                    m => ((WoWMissile)m).ImpactPosition,
                    () => WoWMissile.InFlightMissiles.Where(m => boss != null && boss.IsValid && m.CasterGuid == boss.Guid && m.SpellId == spiritGaleSpellId)));
        }

        [EncounterHandler(64838, "Hooded Crusader", Mode = CallBehaviorMode.Proximity)]
        public Composite HoodedCrusaderEncounter()
        {
            return new PrioritySelector(new Decorator<WoWUnit>(unit => unit.QuestGiverStatus == QuestGiverStatus.Available, ScriptHelpers.CreatePickupQuest(64838)));
        }

        [EncounterHandler(64842, "Lilian Voss", Mode = CallBehaviorMode.Proximity)]
        public Composite LilianVossEncounter()
        {
            return new PrioritySelector(new Decorator<WoWUnit>(unit => unit.QuestGiverStatus == QuestGiverStatus.TurnIn, ScriptHelpers.CreateTurninQuest(64842)));
        }

        [EncounterHandler(64839, "Lilian Voss", Mode = CallBehaviorMode.Proximity)]
        public Composite LilianVossEncounter2()
        {
            return new PrioritySelector(new Decorator<WoWUnit>(unit => unit.QuestGiverStatus == QuestGiverStatus.TurnIn, ScriptHelpers.CreateTurninQuest(64839)));
        }

        [EncounterHandler(59223, "Brother Korloff", Mode = CallBehaviorMode.Proximity, BossRange = 100)]
        public Composite BrotherKorloffEncounter()
        {
            WoWUnit boss = null;
            const int blazingFists = 114807;
            WoWUnit[] trash = null;

            return new PrioritySelector(
                ctx =>
                {
                    boss = ctx as WoWUnit;
                    trash = ScriptHelpers.GetUnfriendlyNpsAtLocation(() => boss.Location, 40, u => u.Entry != BrotherKorloffId).ToArray();
                    return boss;
                },
                ScriptHelpers.CreateRunAwayFromBad(
                    ctx => boss != null && boss.IsValid && !boss.Combat && boss.IsAlive && trash != null && trash.Any(t => t.Location.Distance(boss.Location) < 25), 30, BrotherKorloffId),

                new Decorator(ctx => !boss.Combat && trash.Any() && Me.IsTank() && !Me.Combat,
                    new PrioritySelector(
                        new Decorator(ctx => trash.Any(t => t.Location.Distance(boss.Location) >= 25),
                            ScriptHelpers.CreateClearArea(() => boss.Location, 40, u => u != boss && u.Location.Distance(boss.Location) >= 25)),

                        new Decorator(ctx => !trash.Any(t => t.Location.Distance(boss.Location) >= 25),
                            new ActionAlwaysSucceed()))),


                ScriptHelpers.CreateRunAwayFromBad(ctx => true, 10, u => u.Entry == BrotherKorloffId && u.ToUnit().CastingSpellId == FirestormKickId),
                ScriptHelpers.CreateRunAwayFromBad(ctx => true, 6, u => u.Entry == BrotherKorloffId && u.ToUnit().CastingSpellId == blazingFists, u => u.Location.RayCast(u.Rotation, 3)),
                ScriptHelpers.CreateRunAwayFromBad(ctx => true, 3, ScorchedEarth));
        }

        [ObjectHandler(214296, "Blade of the Anointed")]
        public Composite BladeoftheAnointedHandler()
        {
            WoWGameObject blade = null;

            return new PrioritySelector(ctx => blade = ctx as WoWGameObject,
                new Decorator(ctx => blade.CanLoot,
                    ScriptHelpers.CreateInteractWithObject(() => blade, 2)));
        }

        private const uint BladeOfTheAnointedId = 64855; // WoWUnit version.

        [EncounterHandler(64855, "Blade of the Anointed", Mode = CallBehaviorMode.Proximity)]
        public Composite BladeoftheAnointedEncounter()
        {
            WoWUnit blade = null;

            return new PrioritySelector(ctx => blade = ctx as WoWUnit,
                new Decorator(ctx => blade.QuestGiverStatus == QuestGiverStatus.TurnIn && Targeting.Instance.IsEmpty() && !ScriptHelpers.WillPullAggroAtLocation(blade.Location),
                    ScriptHelpers.CreateTurninQuest(BladeOfTheAnointedId)),

                new Decorator(ctx => blade.QuestGiverStatus == QuestGiverStatus.Available && Targeting.Instance.IsEmpty() && !ScriptHelpers.WillPullAggroAtLocation(blade.Location),
                    ScriptHelpers.CreatePickupQuest(BladeOfTheAnointedId))
                    );
        }

        [LocationHandler(836.4258f, 605.6751f, 13.26288f, 30, "Pull Groups out of chapel")]
        public Composite ClearChapelBehavior()
        {
            var waitLoc = new WoWPoint(836.4258f, 605.6751f, 13.26288f);
            var pullToLoc = new WoWPoint(837.4616, 590.2504, 13.28209);

            WoWUnit pullUnit = null;
            return new PrioritySelector(
                ctx => pullUnit = ScriptHelpers.GetUnfriendlyNpsAtLocation(() => waitLoc, 40).FirstOrDefault(),
                ScriptHelpers.CreatePullNpcToLocation(ctx => !ScriptHelpers.IsBossAlive("Brother Korloff") && pullUnit != null, ctx => true, () => pullUnit, () => pullToLoc, () => waitLoc, 5)
                );
        }

        private bool _checkForZealot = false;
        [EncounterHandler(60040, "Commander Durand", Mode = CallBehaviorMode.Proximity)]
        public Composite CommanderDurandEncounter()
        {
            WoWUnit zealot = null;
            return new PrioritySelector(
                // kill the scarlet zealot that rezes a Judicator before engaging Commander Durand.
                new Decorator(ctx => Me.IsTank() && !Me.Combat && !_checkForZealot,
                    new PrioritySelector(
                        new Decorator(ctx => Me.Location.Distance(_scarletZealotLoc) <= 30,
                            new Action(context => _checkForZealot = true)),

                        new Decorator(ctx => Me.Location.Distance(_scarletZealotLoc) > 30,
                            new Action(context => ScriptHelpers.MoveTankTo(_scarletZealotLoc)))
                        ))
                );
        }

        [EncounterHandler(3977, "High Inquisitor Whitemane")]
        public Composite HighInquisitorWhitemaneEncounter()
        {
            WoWUnit boss = null;
            const int massResurrection = 113134;
            const int heal = 12039;
            return new PrioritySelector(ctx => boss = ctx as WoWUnit,
                ScriptHelpers.CreateInterruptCast(() => boss, massResurrection, heal),
                ScriptHelpers.CreateDispellParty("Power Word: Shield", ScriptHelpers.PartyDispellType.Magic));
        }
    }
}